import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/sequelize';
import { RESPONSE_CODE } from "@/enums/code";
import { Menu } from './menu.model';
import { RoleMenu } from './role_menu.model';
import { Action } from './action.model';
import { UsersService } from '@/modules/admin/users/users.service'
import {
  CreateModuleDto,
  UpdateModuleDto,
  UpdateModuleStatusDto,
  CreateUsinghandledefDto,
  UpdateUsinghandledefDto,
  GetRoleModulesDto,
  UpdateModulesDto
} from './module.dto'
import { getUuidString, generateModuleId } from '@/utils/uuid';

const transformTree = (menus: any[], parentId: string | null): any[] => {
  if (!parentId) return [];
  const map: { [key: string]: any } = {};
  const roots: any[] = [];
  const items = menus.filter((item) => item.dataValues.parentId !== "-1");

  items.forEach((item) => {
    const {
      moduleId,
      path,
      parentId,
      projectCode,
      redirect,
      weight,
      typeStatus,
      icon,
      moduleName,
      quickNavigationIcon,
      modelClassify,
      modType,
    } = item.dataValues;
    map[moduleId] = {
      component: path,
      id: moduleId,
      name: `module_${moduleId}`,
      path: `/module/${moduleId}`,
      parentId,
      projectCode,
      redirect,
      weight,
      meta: {
        hideMenu: Boolean(typeStatus),
        icon,
        title: moduleName,
        quickNavigationIcon,
        moduleId,
        modelClassify,
        modType,
      },
      children: [],
    };
  });
  items.forEach((item) => {
    const { parentId, moduleId } = item.dataValues;
    if (map[parentId]) {
      map[parentId].children.push(map[moduleId]);
    } else {
      roots.push(map[moduleId]);
    }
  });
  return roots.filter((root) => root.parentId === parentId);
};

const buildTree = (items: any[]): any[] => {
  const map: { [key: string]: any } = {};
  const roots: any[] = [];

  items.forEach((item) => {
    map[item.dataValues.moduleId] = {
      id: item.dataValues.moduleId,
      name: item.dataValues.moduleName,
      label: item.dataValues.moduleName,
      menuType: item.dataValues.menuType,
      icon: item.dataValues.icon,
      path: item.dataValues.path,
      parentId: item.dataValues.parentId,
      redirect: item.dataValues.redirect,
      sortOrder: item.dataValues.typeOrder,
      statisticsUrl: item.dataValues.statisticsUrl,
      typeStatus: item.dataValues.typeStatus,
      visible: item.dataValues.visible,
      weight: item.dataValues.typeOrder,
      children: [],
    };
  });
  items.forEach((item) => {
    if (map[item.dataValues.parentId]) {
      map[item.dataValues.parentId].children.push(
        map[item.dataValues.moduleId]
      );
    } else {
      roots.push(map[item.dataValues.moduleId]);
    }
  });
  //  递归清空空的children
  const cleanTree = (nodes: any[]): any[] => {
    return nodes.map((node) => {
      if (node.children.length === 0) {
        delete node.children;
      } else {
        node.children = cleanTree(node.children);
      }
      return node;
    });
  };
  return cleanTree(roots);
};

@Injectable()
export class ModuleService {
  constructor(
    @InjectModel(Menu)
    private menuModel: typeof Menu,

    @InjectModel(RoleMenu)
    private roleMenuModel: typeof RoleMenu,

    @InjectModel(Action)
    private actionModel: typeof Action,

    private usersService: UsersService,
  ) { }

  /**
   * 添加module
   * @param createModuleDto CreateModuleDto
   * @method post
   */
  async addModule(createModuleDto: CreateModuleDto) {
    const id = getUuidString()
    const moduleId = generateModuleId();
    await this.menuModel.create({
      ...createModuleDto,
      id,
      moduleId,
      parentId: createModuleDto.parentId || "-1",
      extMeta: JSON.stringify(createModuleDto.extMeta)
    })

    return {
      code: RESPONSE_CODE.SUCCESS,
      data: [],
      msg: null,
    }
  }

  /**
   * 更新module
   * @param updateModuleDto UpdateModuleDto
   * @method post
   */
  async updateModule(updateModuleDto: UpdateModuleDto) {
    await this.menuModel.update({
      ...updateModuleDto,
      quickNavigationIcon: typeof updateModuleDto.quickNavigationIcon === 'object'
        ? updateModuleDto.quickNavigationIcon[0].url
        : "",
      extMeta: JSON.stringify(updateModuleDto.extMeta)
    }, {
      where: {
        moduleId: updateModuleDto.moduleId,
      }
    })

    return {
      code: RESPONSE_CODE.SUCCESS,
      data: [],
      msg: null,
    }
  }

  /**
   * 更新module status
   * @param updateModuleStatusDto UpdateModuleStatusDto
   * @method post
   */
  async updateModuleStatus(updateModuleStatusDto: UpdateModuleStatusDto) {
    await this.menuModel.update({
      typeStatus: updateModuleStatusDto.status
    }, {
      where: {
        moduleId: updateModuleStatusDto.moduleId,
      }
    })

    return {
      code: RESPONSE_CODE.SUCCESS,
      data: [],
      msg: null,
    }
  }

  /**
   * 获取用户module
   * @param parentId string
   * @method get
   */
  async getUserModules(parentId: string) {
    const menus = await this.menuModel.findAll({
      order: [["typeOrder", "ASC"]],
    });
    const tree = transformTree(menus, parentId);

    return {
      code: RESPONSE_CODE.SUCCESS,
      data: tree,
      msg: null,
    }
  }


  /**
   * 获取用户module
   * @param parentId string
   * @method get
   */
  async getUserMainModules(userId: number) {
    // 查询用户id
    const _user = await this.usersService.findUserInfo(userId)
    if (!_user) {
      return {
        code: RESPONSE_CODE.SUCCESS,
        data: [],
        msg: null,
      }
    }

    const roleList = _user.role
      ? _user.role.split(",")
      : [];

    const _roleMenus = await this.roleMenuModel.findAll({ where: { roleId: roleList } });
    if (!_roleMenus.length) {
      return {
        code: RESPONSE_CODE.SUCCESS,
        data: [],
        msg: null,
      };
    }

    const moudleIds = Array.from(
      new Set(
        _roleMenus
          .map((item) => item.dataValues.checkedKeys)
          .filter(Boolean)
          .flatMap((str) => str.split(","))
      )
    );
    const menus = await this.menuModel.findAll({
      where: {
        parentId: "-1",
        moduleId: moudleIds,
      },
      order: [["typeOrder", "ASC"]],
    });

    const data = menus.map((item) => {
      const {
        path,
        moduleId,
        projectCode,
        moduleName,
        icon,
        redirect,
        visible,
        quickNavigationIcon,
        modelClassify,
      } = item.dataValues;

      return {
        component: path,
        name: `module_${moduleId}`,
        path: "",
        projectCode,
        redirect,
        meta: {
          hideMenu: !Boolean(visible),
          icon,
          title: moduleName,
          quickNavigationIcon,
          moduleId,
          modelClassify,
          modType: null,
        },
      };
    });

    return {
      code: RESPONSE_CODE.SUCCESS,
      data,
      msg: null,
    }
  }

  /**
   * 获取module tree
   * @param 
   * @method get
   */
  async getModuleTree() {
    const menus = await this.menuModel.findAll({
      order: [["typeOrder", "ASC"]],
    });
    const tree = buildTree(menus);
    return {
      code: RESPONSE_CODE.SUCCESS,
      data: tree,
      msg: null,
    }
  };

  /**
  * 获取module详情
  * @param 
  * @method get
  */
  async getModuleInfo(moduleId: string) {
    const _module = await this.menuModel.findOne({
      where: {
        moduleId,
      },
      include: [
        {
          model: Action,
          attributes: [
            "id",
            "parentId",
            "handleCode",
            "name",
            "summary",
            "moduleId",
            "weight",
            "href",
            "dataModelId",
            "modelClassify",
            "workflowTemplateId",
            "bgColor",
            "title",
            "bindImg",
            "modelId",
          ],
        },
      ],
    });
    if (!_module) {
      return {
        code: RESPONSE_CODE.SUCCESS,
        data: null,
        msg: null,
      }
    }

    const module = {
      ..._module?.dataValues,
      factoryId: _module?.dataValues.factoryId ?? undefined,
      extMeta: JSON.parse(_module?.dataValues.extMeta),
    };
    const moduleUserTypes = [
      {
        moduleId,
        flagDesc: "普通用户",
        roles: null,
        summary: null,
        userFlag: 0,
        userRoles:
          "超级管理员;普通用户;全体员工;行政人事;财务人员;测试角色;平台管理员;门户测试",
      },
    ];
    return {
      code: RESPONSE_CODE.SUCCESS,
      data: {
        module,
        moduleUserTypes,
        usingHandles: _module?.dataValues.actions.map(
          (item: any) => item.dataValues
        ),
      },
      msg: null,
    }
  };

  /**
   * 获取角色module
   * @param 
   * @method get
   */
  async getRoleModules(getRoleModulesDto: GetRoleModulesDto) {
    const { roleId, client } = getRoleModulesDto;
    const keys = await this.roleMenuModel.findOne({
      where: { roleId: +roleId, client: +client },
    });
    const menus = await this.menuModel.findAll({
      order: [["typeOrder", "ASC"]],
    });

    const tree = buildTree(menus);
    return {
      code: RESPONSE_CODE.SUCCESS,
      data: {
        checkedKeys: keys ? keys.dataValues.checkedKeys.split(",") : [],
        tree,
      },
      msg: null,
    }
  };

  /**
  * 更新角色module
  * @param 
  * @method get
  */
  async updateRoleModules(roleId: string, updateModulesDto: UpdateModulesDto) {
    const [record, created] = await this.roleMenuModel.findOrCreate({
      where: {
        roleId: +roleId,
        client: updateModulesDto.client,
      },
      defaults: {
        checkedKeys: updateModulesDto.checkedKeys.join(","),
      },
    });
    if (!created) {
      await record.update({ checkedKeys: updateModulesDto.checkedKeys.join(",") });
    }
    return {
      code: RESPONSE_CODE.SUCCESS,
      data: null,
      msg: null,
    }
  };

  /**
  * 获取module 日志
  * @param 
  * @method post
  */
  async addModuleLog() {
    return {
      code: RESPONSE_CODE.SUCCESS,
      data: null,
      msg: null,
    }
  };

  /*********** usinghandledef *************** */
  /**
 * 获取module权限
 * @param moduleId string
 * @method get
 */
  async getAuthByModuleId(moduleId: string) {
    const actions = await this.actionModel.findAll({ where: { moduleId } });
    const data = actions.map((item) => item.dataValues.handleCode)
    return {
      code: RESPONSE_CODE.SUCCESS,
      data,
      msg: null,
    };
  };

  /**
  * 添加usinghandledef
  * @param createUsinghandledefDto CreateUsinghandledefDto
  * @method post
  */
  async addUsinghandledef(createUsinghandledefDto: CreateUsinghandledefDto) {
    await this.actionModel.create({
      ...createUsinghandledefDto,
      name: createUsinghandledefDto.handleName,
    });
    return {
      code: RESPONSE_CODE.SUCCESS,
      data: null,
      msg: null,
    };
  };

  /**
  * 详情usinghandledef
  * @param moduleId string
  * @method get
  */
  async getUsinghandledefInfo(id: number) {
    const info = await this.actionModel.findByPk(id);
    const data = info ? {
      ...info.dataValues,
      handleName: info.dataValues.name,
      depth: info.dataValues.deptId,
      handleId: info.dataValues.id,
      handleLevel: null,
      isGen: 0,
      logFlag: null,
      onclick: null,
      roleIds: null,
      rootId: null,
      tenantId: "1",
    } : null;
    return {
      code: RESPONSE_CODE.SUCCESS,
      data,
      msg: null,
    };
  };

  /**
  * 更新usinghandledef
  * @param updateUsinghandledefDto UpdateUsinghandledefDto
  * @method post
  */
  async updateUsinghandledef(updateUsinghandledefDto: UpdateUsinghandledefDto) {
    await this.actionModel.update(
      { ...updateUsinghandledefDto },
      { where: { id: updateUsinghandledefDto.id } }
    );
    return {
      code: RESPONSE_CODE.SUCCESS,
      data: null,
      msg: null,
    };
  };
}
